<template>
  <div class="bg-white border p-1 rounded border-gray-200 mb-2">
    <div class="mb-1">买入</div>
    <audio ref="audioSuccess">
      <source src="./audio/bought.mp3" type="audio/ogg">
    </audio>
    <a-form label-align="left" :label-col="{span:8}" :wrapper-col="{span:16}">
      <a-form-item label="降价百分比" class="!mb-1">
        <a-input-number addon-after="%"
          v-model:value="pricePercent"
          :min="0" :step="0.1"
          :disabled="props.disabled"
          @change="actionPricePercentChange"
        ></a-input-number>
      </a-form-item>

      <a-form-item label="买入价格" class="!mb-1">
        <a-input :value="price.toString()" disabled />
      </a-form-item>

      <a-form-item label="买入金额" class="!mb-1">
        <a-input-number v-model:value="usdtAmount" addon-after="USDT"
          :disabled="props.disabled"
        ></a-input-number>
      </a-form-item>

      <a-form-item label="买入数量" class="!mb-1">
        <a-input :value="quantity.toFixed(8)" disabled />
      </a-form-item>

      <a-form-item label="撤单价格差" class="!mb-1">
        <a-input-number v-model:value="orderCancelPriceDiff" addon-after="倍"
          :disabled="props.disabled"
          :min="0" :step="0.1"
        ></a-input-number>
      </a-form-item>

      <a-form-item v-if="null === orderId" label="挂单时长" class="!mb-1">
        <a-input-number addon-after="分钟"
          v-model:value="orderDurationLimit"
          :disabled="props.disabled"
          :min="0" :step="1"
        ></a-input-number>
      </a-form-item>

      <a-form-item v-if="orderDuration" label="挂单时长" class="!mb-1">
        <a-input :value="orderDuration" disabled />
      </a-form-item>

      <a-form-item v-if="orderFillSize" label="成交量" class="!mb-1">
        <a-input :value="orderFillSize" disabled />
      </a-form-item>

      <a-form-item class="!mb-1 !mt-2" :wrapper-col="{span:24}">
        <a-button class="w-full" type="primary"
          :loading="orderId != null"
          :disabled="props.disabled"
          @click="actionBuy"
        >买入</a-button>
      </a-form-item>

      <a-form-item v-if="null !== orderId && '' !== orderId" class="!mb-1" :wrapper-col="{span:24}">
        <a-button class="w-full" danger :loading="orderIsCanceling" @click="actionOrderCancel">撤单</a-button>
      </a-form-item>
    </a-form>
  </div>
</template>
<script setup>
import { inject, nextTick, ref, watch } from 'vue';
import { Modal, message } from 'ant-design-vue';
import OkxRestService from './OkxRestService.js';
import Common from './Common.js';
import Decimal from 'decimal.js';
/** @var {Function} */
const emits = defineEmits(['start','success', 'failed','update:price-bought']);
/** @var {Object} */
const props = defineProps({
    basePrice: {type: Decimal, default: new Decimal(0)},
    priceBought : {type: Decimal, default: new Decimal(0)},
    currentPrice : {type: Decimal,default: 0},
    instId : {type: String,default: 'BTC-USDT'},
    disabled : {type: Boolean,default: false},
});
/** @var {number} */
const pricePercent = ref(0.5);
/** @var {number} */
const price = ref(new Decimal(0));
/** @var {number} */
const usdtAmount = ref(10);
/** @var {number} */
const quantity = ref(new Decimal(0));
/** @var {String} */
const orderId = ref(null);
/** @var {String} */
const orderDuration = ref(null);
/** @var {Number} */
const orderDurationLimit = ref(5);
/** @var {String} */
const orderFillSize = ref(null);
/** @var {boolean} */
const orderIsCanceling = ref(false);
/** @var {number} */
const orderCancelPriceDiff = ref(2);
/** @var {TickerChart} */
const tickerChart = inject('tickerChart');
/** @var {HtmlElement} */
const audioSuccess = ref(null);
watch(() => [props.basePrice, pricePercent.value, usdtAmount.value], handlePriceAndSizeUpdateRequired);
// define expose
defineExpose({autoBuy});

// auto buy
function autoBuy() {
    // 这里应该有策略配置 ~~~
    setTimeout(() => {
        actionBuy();
    }, 1000 * 30);
}

// 监视订单状态并自动处理
async function orderMonitorAndProcess( options ) {
    let service = OkxRestService.getInstance();
    let orderInfo = await service.tradeOrderGet(props.instId, options.orderId);

    // 订单状态为挂单
    if ( 'live' === orderInfo.state ) {
        let diffSeconds = Math.floor((Date.now() - options.startedAt) / 1000);
        let orderDurationLimitText = '--:--';

        // 检查挂单时间是否超时
        if ( 0 < orderDurationLimit.value ) {
            let limitSec = orderDurationLimit.value * 60;
            orderDurationLimitText = Common.numberFormatAsDuration(limitSec);
            if ( diffSeconds > limitSec ) { // 挂单时间超时则撤销订单
               message.warning("买入 : 挂单超时, 撤单中...");
               await actionOrderCancel();
               emits('failed');
               return true;
            }
        }

        // 检查价格差是否超出范围 : (当前价格 - 基础价格) / (基础价格 - 买入价格)
        // 当价格差距太大时，涨的太多，要么长时间不会降下来， 要么突然掉下来击穿卖出时的止损价格
        let currentPriceDiff = props.currentPrice.minus(props.basePrice);
        console.log('Current Price Diff : ', currentPriceDiff.toString());
        if ( orderCancelPriceDiff.value > 0 && currentPriceDiff.greaterThanOrEqualTo(0) ) {
            let boughtPriceDiff = (new Decimal(orderInfo.px)).minus(props.basePrice).abs();
            let diffTimes = currentPriceDiff.div(boughtPriceDiff);
            console.log(`OrderCancelPriceDiff(${orderCancelPriceDiff.value}) Check : buy=${boughtPriceDiff.toString()}; cur=${currentPriceDiff.toString()}; tim=${diffTimes.toString()}`,);
            if ( diffTimes.greaterThanOrEqualTo(orderCancelPriceDiff.value) ) {
                message.warning("买入 : 当前价格超出范围, 撤单中...");
                await actionOrderCancel();
                emits('failed');
                return true;
            }
        }

        let durationText = Common.numberFormatAsDuration(diffSeconds);
        orderDuration.value = `${durationText}/${orderDurationLimitText}`;
        await Common.sleep(1000);
        return false;
    }

    // 订单状态为成交
    if (orderInfo.state == 'filled' ) {
        let now = Date.now();
        tickerChart.value.markPointSet(`buy-${now}`, now, props.currentPrice.toString(), {symbol: 'arrow', color:'green'});
        emits('success', price.value);
        message.success("买入 : 完成");
        audioSuccess.value.play();
        return true;
    }

    // 订单被关闭，这里可能是被手动撤单
    if ( orderInfo.state == 'canceled' ) {
        emits('failed');
        message.info("买入 : 已取消");
        return true;
    }

    // 订单状态为部分成交
    if ( 'partially_filled' === orderInfo.state ) {
        orderFillSize.value = `${orderInfo.fillSz} / ${orderInfo.sz}`;
        message.info(`买入 : ${orderInfo.fillSz} / ${orderInfo.sz}`);
        await Common.sleep(1000);
        return false ;
    }

    // 订单状态未知
    Modal.error({title: '下单失败', content: `未知订单状态: ${orderInfo.state}`});
    return true;
}

// handle price update required
function handlePriceAndSizeUpdateRequired() {
    let newPrice = props.basePrice;
    price.value = newPrice.minus(newPrice.times(new Decimal(pricePercent.value).div(100))); // newPrice - (newPrice * (pricePercent.value / 100))
    quantity.value = new Decimal(usdtAmount.value).div(price.value);
    tickerChart.value.markLineSet('buy', price.value.toString(), {name:'买入', color:'gray'});
    emits('update:price-bought', price.value);
}

// action buy
async function actionBuy() {
    emits('start', props.basePrice);
    await nextTick();

    tickerChart.value.markLineSet('buy', price.value.toString(), {name:'买入', color:'gray'});
    orderId.value = '';

    // 买入下单
    let order = null;
    try {
        let buyPrice = price.value.toString();
        let buySize = quantity.value.toString();
        let service = OkxRestService.getInstance();
        order = await service.tradeOrderBuyLimit(props.instId, buyPrice, buySize);
        orderId.value = order.ordId;
        message.info("买入 : 已下单");
    } catch ( e ) {
        orderId.value = null;
        emits('failed');
        Modal.error({title: '下单失败', content: e.message});
        return ;
    }

    // 监视订单状态
    let hasProcessed = false;
    let timeStart = Date.now();
    do {
        let mpOptions = {};
        mpOptions.startedAt = timeStart;
        mpOptions.orderId = order.ordId;
        hasProcessed = await orderMonitorAndProcess(mpOptions);
    } while( !hasProcessed );

    // 清理买入状态
    orderDuration.value = null;
    orderFillSize.value = null;
    orderId.value = null;
}

// action order cancel
async function actionOrderCancel() {
    orderIsCanceling.value = true;
    let service = OkxRestService.getInstance();
    try {
        await service.tradeOrderCancel(props.instId, orderId.value);
    } catch ( e ) {
        orderIsCanceling.value = false;
        Modal.error({title: '撤单失败', content: e.message});
        return ;
    }
    orderId.value = null;
    orderDuration.value = null;
    orderFillSize.value = null;
    orderIsCanceling.value = false;
}

// action price percent change
function actionPricePercentChange() {
    tickerChart.value.yAxisRangeAutoFit();
}
</script>
